/*
 * Created on 2005-4-27
 *
 */
package util;

import java.beans.IndexedPropertyDescriptor;
import java.beans.PropertyDescriptor;
import java.sql.ResultSet;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.Iterator;

import org.apache.commons.beanutils.PropertyUtils;

/**
 * @author 
 *
 * 进行OR转换的工具类，提供一些常用函数便于进行OR转换
 */

public class ObjectRelationMappingUtil
{
    //方便初始化ORM信息一些函数
    /**
     * 此函数帮助生成一个个类进行OR转换的ORProperty集合
     * @param bean 该类的一个实例
     * @param propertyName 该类的一个属性名
     * @param fieldName 该属性名在数据库表中对应的字段名
     * @param properties ORProperty集合对象，暂限定为Vector
     */
    public static void addORProperty(Object bean, String propertyName, String fieldName, Collection properties)
    {
        ORProperty orProperty = new ORProperty();
        orProperty.setPropertyName(propertyName);
        orProperty.setFieldName(fieldName);
        try
        {
            PropertyDescriptor desc = PropertyUtils.getPropertyDescriptor(bean, propertyName);
            if (desc == null)
            {
                orProperty.setIndexed(false);
                orProperty.setFieldType(ORProperty.FIELD_TYPE_STRING);
            }
            else if (desc instanceof IndexedPropertyDescriptor)
            {
                orProperty.setIndexed(true);
                orProperty.setFieldType(ORProperty.getType(((IndexedPropertyDescriptor)desc).getIndexedPropertyType()));
            }
            else
            {
                orProperty.setIndexed(false);
                orProperty.setFieldType(ORProperty.getType(desc.getPropertyType()));
            }
        }
        catch (Exception e)
        {
            System.out.println("addORProperty(Object, String , String, Vector) in FreewayAdUtil");
            System.out.println(e.getMessage());
            e.printStackTrace();
            orProperty.setIndexed(false);
            orProperty.setFieldType(ORProperty.FIELD_TYPE_STRING);
        }
        properties.add(orProperty);
    }
    
    /**
     * 由于indexed和fieldType决定了ORProperty类各方法能否正常执行，上一个方法通过reflect机制
     * 确定这两个属性值，但是有可能出差错，如果实际执行中出现问题，只能改用此方法对每个ORProperty属性
     * 手工设置
     * @param propertyName 要转换java bean的一个属性名
     * @param indexed 该属性是否为index类型
     * @param fieldType 该属性对应数据库表的字段类型
     * @param fieldName 该属性对应数据库表的字段名
     * @param autoIncrement 该属性是否由数据库系统维护，若是，则不出现在insert语句中
     * @param properties ORProperty集合对象，暂限定为Vector
     */
    public static void addORProperty(String propertyName, boolean indexed, int fieldType, String fieldName, boolean autoIncrement, Collection properties)
    {
        ORProperty orProperty = new ORProperty();
        orProperty.setPropertyName(propertyName);
        orProperty.setIndexed(indexed);
        orProperty.setFieldType(fieldType);
        orProperty.setFieldName(fieldName);
        orProperty.setAutoIncrement(autoIncrement);
        properties.add(orProperty);
    }

    /**
     * sql语句映射函数，被映射函数要实现ObjectRelationMappable接口
     * 生成一条insert语句，index对该对象中所有index类型的属性有效
     * 
     * @param object
     * @return
     */
    public static String getObjectInsertSQL(ObjectRelationMappable object)
    {
        StringBuffer insert = new StringBuffer();
        insert.append("insert into ");
        insert.append(object.getTableName()+"(");
        Iterator propertiesItr = object.getORProperties().iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            if (property.isAutoIncrement())
                continue;
            insert.append(property.getFieldName());
            if (propertiesItr.hasNext())
                insert.append(", ");
            else
                insert.append(")");
        }
        insert.append(" values (");
         propertiesItr = object.getORProperties().iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            if (property.isAutoIncrement())
                continue;
            insert.append(property.getInsertForm(object));
            if (propertiesItr.hasNext())
                insert.append(", ");
            else
                insert.append(")");
        }
        return insert.toString();
    }
    /**
     * sql语句映射函数，被映射函数要实现ObjectRelationMappable接口
     * 生成一条insert语句，index对该对象中所有index类型的属性有效
     * 
     * @param object
     * @param index
     * @return
     */
    public static String getObjectInsertSQL(ObjectRelationMappable object,int index)
    {
        StringBuffer insert = new StringBuffer();
        insert.append("insert into ");
        insert.append(object.getTableName());
        insert.append(" values (");
        Iterator propertiesItr = object.getORProperties().iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            if (property.isAutoIncrement())
                continue;
            insert.append(property.getInsertForm(object, index));
            if (propertiesItr.hasNext())
                insert.append(", ");
            else
                insert.append(")");
        }
        return insert.toString();
    }
    
    /**
     * 生成一条update语句，更新该对象中所有映射属性，update条件由condition变量指定，若指定propertiesToUpdate集合，则仅对
     * 此集合中的属性进行更新
     * 
     * @param object
     * @param condition
     * @return
     */
    public static String getObjectUpdateSQL(ObjectRelationMappable object, String condition)
    {
        StringBuffer update = new StringBuffer();
        update.append("update ");
        update.append(object.getTableName());
        update.append(" set ");
        Iterator propertiesItr = object.getORProperties().iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            if (property.isAutoIncrement())
                continue;
            update.append(property.getUpdateForm(object));
            if (propertiesItr.hasNext())update.append(", ");
        }
        update.append(" where  ");
        update.append(condition);
        return update.toString();
    }
    /**
     * 生成一条update语句，更新该对象中所有映射属性，update条件由condition变量指定，若指定propertiesToUpdate集合，则仅对
     * 此集合中的属性进行更新
     * 
     * @param object
     * @param condition
     * @param index
     * @return
     */
    public static String getObjectUpdateSQL(ObjectRelationMappable object, String condition, int index)
    {
        StringBuffer update = new StringBuffer();
        update.append("update ");
        update.append(object.getTableName());
        update.append(" set ");
        Iterator propertiesItr = object.getORProperties().iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            if (property.isAutoIncrement())
                continue;
            update.append(property.getUpdateForm(object, index));
            if (propertiesItr.hasNext())update.append(", ");
        }
        update.append(" where ");
        update.append(condition);
        return update.toString();
    }
    /**
     * 生成一条update语句，更新该对象中所有映射属性，update条件由condition变量指定，若指定propertiesToUpdate集合，则仅对
     * 此集合中的属性进行更新
     * 
     * @param object
     * @ propertiesToUpdate
     * @param condition
     * @return
     */
    public static String getObjectUpdateSQL(ObjectRelationMappable object, Collection propertiesToUpdate, String condition)
    {
        StringBuffer update = new StringBuffer();
        update.append("update ");
        update.append(object.getTableName());
        update.append(" set ");
        Iterator propertiesItr = propertiesToUpdate.iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = lookup(object.getORProperties(), (String)propertiesItr.next());
            if (property != null && !property.isAutoIncrement())
            {
	            update.append(property.getUpdateForm(object));
	            if (propertiesItr.hasNext())update.append(", ");
            }
        }
        update.append(" where ");
        update.append(condition);
        return update.toString();
        
    }
    /**
     * 生成一条update语句，更新该对象中所有映射属性，update条件由condition变量指定，若指定propertiesToUpdate集合，则仅对
     * 此集合中的属性进行更新
     * 
     * @param object
     * @param propertiestoupdate
     * @param condition
     * @param index
     * @return
     */
    public static String getObjectUpdateSQL(ObjectRelationMappable object, Collection propertiesToUpdate, String condition, int index)
    {
        StringBuffer update = new StringBuffer();
        update.append("update ");
        update.append(object.getTableName());
        update.append(" set ");
        Iterator propertiesItr = propertiesToUpdate.iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = lookup(object.getORProperties(), (String)propertiesItr.next());
            if (property != null && !property.isAutoIncrement())
            {
	            update.append(property.getUpdateForm(object, index));
	            if (propertiesItr.hasNext())update.append(", ");
            }
        }
        update.append(" where ");
        update.append(condition);
        return update.toString();
        
    }
    /**
     * 生成一条update语句，更新该对象中所有映射属性，update条件由condition变量指定，若指定propertiesToUpdate集合，则仅对
     * 此集合中的属性进行更新
     * 
     * @param object
     * @param propertiestoupdate
     * @param condition
     * @return
     */
    public static String getObjectUpdateSQL(ObjectRelationMappable object, Object[] propertiesToUpdate, String condition)
    {
        if (propertiesToUpdate == null)
            return getObjectUpdateSQL(object, condition);
        else
            return getObjectUpdateSQL(object, Arrays.asList(propertiesToUpdate), condition);
    }
    /**
     * 生成一条update语句，更新该对象中所有映射属性，update条件由condition变量指定，若指定propertiesToUpdate集合，则仅对
     * 此集合中的属性进行更新
     * 
     * @param object
     * @param propertiestoupdate
     * @param condition
     * @param index
     * @return
     */
    public static String getObjectUpdateSQL(ObjectRelationMappable object, Object[] propertiesToUpdate, String condition, int index)
    {
        if (propertiesToUpdate == null)
            return getObjectUpdateSQL(object, condition, index);
        else
            return getObjectUpdateSQL(object, Arrays.asList(propertiesToUpdate), condition, index);
    }
    
    /**
     * 针对特定情况的update，指定主键对应的属性名，则生成的update语句更新条件为where <<keyFieldName>>=<<keyPropertyValue>>
     * 如不指定propertiesToUpdate(给定null)，则对所有属性进行更新，当object中含有index类型属性时，index值有效
    */
    public static String getObjectUpdateSQLByKey(ObjectRelationMappable object, Collection propertiesToUpdate, String keyPropertyName, int index)
    {
        ORProperty property = lookup(object.getORProperties(), keyPropertyName);
        if (property == null)return null;
        String condition = property.getUpdateForm(object, index);
        if (propertiesToUpdate == null)
            return getObjectUpdateSQL(object, condition, index);
        else
            return getObjectUpdateSQL(object, propertiesToUpdate, condition, index);
    }
    /**
     * 针对特定情况的update，指定主键对应的属性名，则生成的update语句更新条件为where <<keyFieldName>>=<<keyPropertyValue>>
     * 如不指定propertiesToUpdate(给定null)，则对所有属性进行更新，当object中含有index类型属性时，index值有效
    */
    public static String getObjectUpdateSQLByKey(ObjectRelationMappable object, Object[] propertiesToUpdate, String keyPropertyName, int index)
    {
        if (propertiesToUpdate == null)
            return getObjectUpdateSQLByKey(object, (Collection)null, keyPropertyName, index);
        else
            return getObjectUpdateSQLByKey(object, Arrays.asList(propertiesToUpdate), keyPropertyName, index);
    }
    private static ORProperty lookup(Collection properties, String propertyName)
    {
        Iterator propertiesItr = properties.iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            if (propertyName.equals(property.getPropertyName()))return property;
        }
        return null;
    }
    
    /**
     * ResultSet到Bean的映射函数
     * 将ResultSet中当前行映射到java bean中
     * 
     * @param object
     * @param resultset
     */
    public static void fillinBO(ObjectRelationMappable object, ResultSet resultset)
    {
        Iterator propertiesItr = object.getORProperties().iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            property.setPropertyValue(object, resultset);
        }
    }
    /**
     * ResultSet到Bean的映射函数
     * 将ResultSet中当前行映射到java bean中
     * 
     * @param object
     * @param resultset
     */
    public static void fillinBO(ObjectRelationMappable object, ResultSet resultset, int index)
    {
        Iterator propertiesItr = object.getORProperties().iterator();
        while (propertiesItr.hasNext())
        {
            ORProperty property = (ORProperty)propertiesItr.next();
            property.setPropertyValue(object, resultset, index);
        }
    }
    //
    public static String getSQLForm(Object javaVar)
    {
        StringBuffer SQLForm = new StringBuffer();
        if (javaVar == null)
            return null;
        else if (javaVar instanceof String)
        {
            javaVar = ((String)javaVar).replaceAll("'", "''");//针对注入攻击必须要做的预处理
            SQLForm.append("'");
            SQLForm.append(javaVar);
            SQLForm.append("'");
        } 
        else if (javaVar instanceof Date)
        {
            SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
            SQLForm.append("'");
            SQLForm.append(dateFormat.format(javaVar));
            SQLForm.append("'");
        }
        else if (javaVar instanceof Boolean)
        {
            if (javaVar.equals(Boolean.TRUE))
                SQLForm.append("1");
            else
                SQLForm.append("0");
        } 
        else
            SQLForm.append(javaVar);
        return SQLForm.toString();
    }
}
